home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-01-26 | 7.3 KB | 379 lines | [TEXT/KEEN] |
- # $FuncTree : on a per-file basis, print a list of function definitions
- # as encountered, and for each defined function print a list of functions
- # called by the defined function.
- # -this was written to prototype EnterAct's function call/caller tree indexer.
-
-
- BEGIN {
- init_lexer();
- first_time = 1
- }
-
- FNR == 1 {
- z = split(ARGV[1], names, ":")
- filename = names[z];
-
- curlyCount = 0
- numCalls = 0
- numDefs = 0
- current_function = ""
- could_be_definition = 0
- toktype = ILLEGAL
- line = $0
- if (first_time != 1)
- init_arrays();
- collect_functions();
- print_names();
- first_time = 0
- }
-
- ##END { print_names(); }
-
- function init_arrays( k)
- {
- for (k in func_not_printed)
- delete func_not_printed[k];
- for (k in func_defs)
- delete func_defs[k];
- for (k in func_tree)
- delete func_tree[k];
- }
-
- function collect_functions( type)
- {
- advance();
- while (toktype != EOF)
- {
- if (toktype == NAME)
- {
- type = lookup(tok) # see hAWK User’s Manual 2114 or so
- if (type == 4)
- {
- ##funcs[tok]++
- record_function()
- }
- }
- else if (toktype == "{")
- {
- ++curlyCount;
- if (could_be_definition == 1 && curlyCount == 1)
- {
- func_defs[++numDefs] = current_function
- func_not_printed[current_function] = 1
- func_tree[current_function, ++numCalls] = "T";
- }
- }
- else if (toktype == "}")
- {
- --curlyCount;
- if (curlyCount == 0) # outside a function
- {
- current_function = "";
- could_be_definition = 0;
- }
- }
- else if (curlyCount == 0 && could_be_definition == 1 && toktype == ";")
- could_be_definition = 0;
- advance();
- }
- }
-
- function record_function()
- {
- if (curlyCount == 0) # top level - NOTE could be a prototype for the func
- {
- current_function = tok
- numCalls = 0
- could_be_definition = 1
- }
- else if (current_function != "") # inside a function(?)
- {
- func_tree[current_function, ++numCalls] = tok
- }
- }
-
- # For each function definition in the file, in order of occurrence,
- # print a list of called functions, also in order of occurrence.
- # Only functions which actually call another function are listed,
- # and duplicates are suppressed in the call list.
- function print_names( i, j, k, fn)
- {
- for (i = 1; i <= numDefs; ++i)
- {
- fn = func_defs[i]
- if (((fn, 1) in func_tree) \
- && func_not_printed[fn]) # not a spurious mention, not done yet
- {
- func_not_printed[fn] = 0
- for (k in seen)
- delete seen[k];
- print fn, ":"
- j = 2; # 1 is just to show function is defined
- while ((fn, j) in func_tree)
- {
- tok = func_tree[fn, j]
- if (!(tok in seen))
- {
- print "\t", tok
- seen[tok] = 1
- }
- ++j;
- }
- }
- }
- }
-
- function init_lexer()
- {
- NAME = 256
- STRING = 257
- CHAR_CONSTANT = 258
- NUMBER = 259
- KEY = 260
- BITASSIGNOP = 261
- ASSIGNOP = 262
- LEX_OR = 263
- LEX_AND = 264
- RELOP = 265
- SHIFT = 266
- INCREMENT = 267
- DECREMENT = 268
- POINTER = 269
- OTHER = 270
- EOF = 271
- ILLEGAL = 272
-
- C_KEY["..."] = 1
- C_KEY["asm"] = 1
- C_KEY["auto"] = 1
- C_KEY["break"] = 1
- C_KEY["case"] = 1
- C_KEY["char"] = 1
- C_KEY["class"] = 1
- C_KEY["const"] = 1
- C_KEY["continue"] = 1
- C_KEY["default"] = 1
- C_KEY["delete"] = 1
- C_KEY["do"] = 1
- C_KEY["double"] = 1
- C_KEY["else"] = 1
- C_KEY["enum"] = 1
- C_KEY["extern"] = 1
- C_KEY["float"] = 1
- C_KEY["for"] = 1
- C_KEY["goto"] = 1
- C_KEY["if"] = 1
- C_KEY["int"] = 1
- C_KEY["long"] = 1
- C_KEY["new"] = 1
- C_KEY["Pascal"] = 1
- C_KEY["pascal"] = 1
- C_KEY["register"] = 1
- C_KEY["return"] = 1
- C_KEY["short"] = 1
- C_KEY["signed"] = 1
- C_KEY["sizeof"] = 1
- C_KEY["static"] = 1
- C_KEY["struct"] = 1
- C_KEY["switch"] = 1
- C_KEY["typedef"] = 1
- C_KEY["union"] = 1
- C_KEY["unsigned"] = 1
- C_KEY["virtual"] = 1
- C_KEY["void"] = 1
- C_KEY["volatile"] = 1
- C_KEY["while"] = 1
- }
-
- function advance()
- {
- if (toktype == EOF) return
- if (tok == "." || tok == "->") #member coming, not a local
- {
- if (match(line, /^[A-Za-z_](\w|_)*/))
- {
- tok = substr(line, 1, RLENGTH)
- line = substr(line, RLENGTH+1)
- toktype = OTHER
- return
- }
- else
- error("missing member name")
- }
- toktype = ILLEGAL
- skip_comments_etc()
- if (toktype == EOF || toktype == STRING || toktype == CHAR_CONSTANT)
- return
- if (match(line, /^[A-Za-z_](\w|_)*/) ||
- match(line, /^\.\.\./)) #name or key - note "..." treated as key.
- {
- tok = substr(line, 1, RLENGTH)
- line = substr(line, RLENGTH+1)
- if (tok in C_KEY)
- toktype = KEY
- else
- toktype = NAME
- return
- }
- if (match(line, /^([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)?[fFlL]?/) ||
- match(line, /^0[0-7]+(u|U)?(l|L)?/) ||
- match(line, /^0(x|X)[0-9a-fA-F]+(u|U)?(l|L)?/)) #float or int
- toktype = NUMBER;
- else if (match(line, /^(<<=|>>=|&=|\^=|\|=)/)) #bit assign
- toktype = BITASSIGNOP
- else if (match(line, /^(\+=|-=|\*=|\/=|%=)/)) #assign, inc
- toktype = ASSIGNOP
- else if (match(line, /^\|\|/))
- toktype = LEX_OR
- else if (match(line, /^&&/))
- toktype = LEX_AND
- else if (match(line, /^(<=|==|!=|>=)/)) #relational
- toktype = RELOP
- else if (match(line, /^(<<|>>)/)) #shift
- toktype = SHIFT
- else if (match(line, /^\+\+/))
- toktype = INCREMENT
- else if (match(line, /^--/))
- toktype = DECREMENT
- else if (match(line, /^->/))
- toktype = POINTER
- else if (match(line, /^./)) #everything else
- {
- #TO DO trap illegal tokens, eg "@"
- toktype = substr(line,1,1)
- }
- else
- error("Unexpected empty line")
- tok = substr(line, 1, RLENGTH)
- line = substr(line, RLENGTH+1)
- }
-
- function skip_comments_etc()
- {
- do
- {
- sub(/^[ \t]+/, "", line) #remove leading blanks and tabs
- sub(/^\/\/.*/, "", line) #remove C++ comments
- while (match(line, /^"|^\/\*|^'/))
- {
- if (match(line, /^"/))
- {
- GetString()
- return
- }
- else if (match(line, /^'/))
- {
- GetCharConstant()
- return
- }
- else
- SkipComment()
- sub(/^[ \t]+/, "", line)
- sub(/^\/\/.*/, "", line)
- }
- } while (length(line) == 0 && getline line > 0);
- if (length(line) == 0)
- toktype = EOF
- }
-
- function GetString( len, c, i, temp, esc)
- {
-
- len = length(line)
- i = 2;
- for (esc = 0; i <= len; ++i)
- {
- c = substr(line, i, 1)
- if (c == "\"")
- {
- if (esc == 0 || esc%2 == 0)
- {
- tok = temp substr(line,1,i)
- line = substr(line, i+1)
- toktype = STRING
- return;
- }
- else
- esc = 0
- }
- else if (c == "\\")
- {
- if (i == len) #end of line, string continued
- {
- temp = temp substr(line,1,len-1)
- if (getline line <= 0)
- error("unterminated string")
- else
- {
- esc = 0
- i = 0
- len = length(line)
- if (len == 0)
- error("unterminated string")
- }
- }
- else
- ++esc
- }
- else
- esc = 0
- }
- error("unterminated string")
- }
-
- function GetCharConstant( len, c, i, esc)
- {
- len = length(line)
- i = 2;
- toktype = CHAR_CONSTANT
- for (esc = 0; i <= len; ++i)
- {
- c = substr(line, i, 1)
- if (c == "'")
- {
- if (esc == 0 || esc%2 == 0)
- {
- tok = substr(line,1,i)
- line = substr(line, i+1)
- return;
- }
- else
- esc = 0
- }
- else if (c == "\\")
- ++esc
- else
- esc = 0
- }
- error("unterminated char constant")
- }
-
- function SkipComment( len, c, i)
- {
-
- i = 3;
- do
- {
- for (len = length(line); i <= len; ++i)
- {
- c = substr(line, i, 2)
- if (c == "*/")
- {
- line = substr(line, i+2)
- return;
- }
- }
- i = 1;
- } while (getline line > 0);
- error("unterminated comment")
- }
-
- function error(s)
- {
- print "Error:", s
- print "Location:", filename, NR
- print "Current Line:", line
- print "Current token", tok
- print "Current toktype:", toktype
- exit 1
- }